package game.map;

import game.units.Character;

import java.util.ArrayList;
import java.util.List;

import communication.common.InteractionManager;

import processing.core.PApplet;

public class TiledMapInGame extends TiledMap {
	
	private InteractionManager manager = null;
	
	public TiledMapInGame(PApplet app, InteractionManager manager) {
		super(app);
		this.manager = manager;
	}
	
	public boolean noWallToTheLeft(int x, int y) {
		return inMap(x-1, y, verticalWalls) && verticalWalls[y][x-1] % 2 == 0;
	}
	public boolean noWallToTheRight(int x, int y) {
		return inMap(x, y, verticalWalls) && verticalWalls[y][x] % 2 == 0;
	}
	public boolean noWallAbove(int x, int y) {
		return inMap(x, y-1, horizontalWalls) && horizontalWalls[y-1][x] % 2 == 0;
	}
	public boolean noWallBelow(int x, int y) {
		return inMap(x, y, horizontalWalls) && horizontalWalls[y][x] % 2 == 0;
	}
	
	private boolean inMap(int x, int y, int[][] walls) {
		return x >= 0 && x < walls[0].length && 
				y >= 0 && y < walls.length;
	}
	
	public void informDoorActions(int x, int y, boolean vertical, boolean open) {
		
		int[][] walls = (vertical) ? verticalWalls : horizontalWalls;
		if (x > 0 && x < walls[0].length - 1 && y > 0 && y < walls.length - 1) {
		
			// Close door
			if (walls[y][x] == 2 && !open) {
				walls[y][x] = 3;
			}
			// Open door
			else if (walls[y][x] == 3 && open) {
				walls[y][x] = 2;
			}
		}
	}
	
	public String doorActions(int x, int y, int[][] walls, boolean vertical) {
		
		if (x < 0 || x > walls[0].length - 1 
				|| y < 0 || y > walls.length - 1)
			return null;
		
		if (walls[y][x] == 2) {
			walls[y][x] = 3;
			manager.setDoorStatus(x, y, vertical, false);
			return "closes";
		} else if (walls[y][x] == 3) {
			walls[y][x] = 2;
			manager.setDoorStatus(x, y, vertical, true);
			return "opens";
		}
		return "";
		
	}
	
	public int[][] getVerticalWalls() {
		return verticalWalls;
	}

	public int[][] getHorizontalWalls() {
		return horizontalWalls;
	}
	
	public void draw(int[][] visibility) {
		
		if (visibility == null) {
			drawBackground();
			super.draw();
			return;
		}
		
		// tile side length
		side = app.getHeight() / zoom;
		int w = tilesX * side;
		int h = tilesY * side;
		
		// draw background image
		app.image(backgroundImg, 0, 0);

		// the grid... a final frontier...
		app.strokeWeight(1);
		app.stroke(Static.CYAN);
		for (int i = side; i < h; i += side)
			app.line(0, i, w, i);
		for (int j = side; j < w; j += side)
			app.line(j, 0, j, h);
		
		// draw border walls
		app.strokeWeight(4);
		app.stroke(Static.lightCyan);
		app.line(0, 0, 0, h);
		app.line(w, 0, w, h);
		app.line(0, 0, w, 0);
		app.line(0, h, w, h);
		
		// paint background image with black squares
		app.fill(0);
		app.noStroke();
		for (int i = 0; i < visibility.length; i++)
			for (int j = 0; j < visibility[0].length; j++)
				if (visibility[i][j] == 0)
					app.rect(i*side, j*side, side, side);
		
		// draw vertical walls and doors
		for (int i = 0; i < verticalWalls.length; i++)
			for (int j = 0; j < verticalWalls[0].length; j++) {
				if (visibility[j][i] == 1 || (i < visibility.length + 1 &&
						visibility[j+1][i] == 1)) { //j >= 1 && 
					if (verticalWalls[i][j] == WALLS) {
						app.stroke(Static.lightCyan);
						app.line(j*side+side, i*side, j*side+side, i*side+side);
					} else {
						app.stroke(Static.YELLOW);
						if (verticalWalls[i][j] == CLOSEDDOOR)
							app.line(j*side+side, i*side, j*side+side, i*side+side);
						else if (verticalWalls[i][j] == OPENDOOR)
							app.line(j*side+side, i*side, j*side+side - 10, i*side+side - 10);
					}
				}
			}

		// draw horizontal walls and doors
		for (int i = 0; i < horizontalWalls[0].length; i++)
			for (int j = 0; j < horizontalWalls.length; j++) {
				if (visibility[i][j] == 1 || (j < visibility[0].length - 1 &&
						visibility[i][j+1] == 1)) {
					if (horizontalWalls[j][i] == WALLS) {
						app.stroke(Static.lightCyan);
						app.line(i*side, j*side+side, i*side+side, j*side+side);
					} else {
						app.stroke(Static.YELLOW);
						if (horizontalWalls[j][i] == CLOSEDDOOR)
							app.line(i*side, j*side+side, i*side+side, j*side+side);
						else if (horizontalWalls[j][i] == OPENDOOR)
							app.line(i*side, j*side+side, i*side+side - 10, j*side+side - 10);
					}
				}
			}
		
		// draw units and their extras
		for (MapUnit u : units)
			if (visibility[u.getPlannedX()][u.getPlannedY()] == 1)
				u.draw(app, side);
		for (MapUnit u : units)
			u.drawExtra(app, side, visibility);
				
		for (MapItem i : itens)
			if (visibility[i.getX()][i.getY()] == 1)
			i.draw(app, side);
				
	}

	public void load(String path, List<MapUnit> heroes) {
		super.load(path);
		units.addAll(heroes);
//		this.units = heroes;
	}

	public void informUnitMovement(long id, int x, int y) {
		MapUnit mu = getMapUnit(id);
		mu.setPosition(x, y);
	}
	
	public List<MapUnit> getHeroes() {
		List<MapUnit> heroes = new ArrayList<MapUnit>();
		for (MapUnit mu : getUnits())
			if (mu.getUnit() instanceof Character)
				heroes.add(mu);
		return heroes;
	}

	public List<MapUnit> getActiveUnits() {
		return activeUnits;
	}

	public void setActiveUnits(List<MapUnit> triggeredUnits) {
		activeUnits.clear(); // talvez sem clear
		activeUnits.addAll(getHeroes());
		activeUnits.addAll(triggeredUnits);
	}
	
	public void setActiveUnits(ArrayList<Long> ids) {
		activeUnits.clear(); // talvez sem clear
		activeUnits.addAll(getHeroes());
		ArrayList<MapUnit> triggeredUnits = new ArrayList<MapUnit>();
		for(Long id : ids) {
			for (MapUnit unit : units) {
				if (unit.getId() == id)
					triggeredUnits.add(unit);
			}
		}
		activeUnits.addAll(triggeredUnits);
	}
	
	public void setActiveUnits() {
		activeUnits.clear();
		activeUnits.addAll(getHeroes());
	}

}

